package xjtu.sad.zbsj.task.annotater.labelTask.Impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xjtu.sad.zbsj.common.PageParam;
import xjtu.sad.zbsj.dao.labelTask.LabelTaskDao;
import xjtu.sad.zbsj.task.annotater.labelTask.*;
import xjtu.sad.zbsj.template.Template;
import xjtu.sad.zbsj.template.TemplateService;

import javax.annotation.Resource;
import java.util.*;

@Service
@Transactional
public class LabelTaskServiceImpl implements LabelTaskService {

    @Resource
    private LabelTaskDao labelTaskDao;

    @Resource
    private TemplateService templateService;

    /**
     * 获得当前用户的所有领取信息
     *
     * @param userId    用户id
     * @param pageParam 分页信息
     * @return 当前用户的所有领取信息
     */
    @Override
    public Page<DrawInfo> getDrawInfo(int userId, PageParam pageParam) {
        try {
            // 开始分页
            PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize());

            List<DrawInfo> drawInfoList = labelTaskDao.getDrawList(userId);
            System.out.println(drawInfoList);
            Page<DrawInfo> pageInfo = (Page<DrawInfo>) drawInfoList;
            Map<Integer, TaskInfo> taskInfoMap = new HashMap<>();

            for (DrawInfo drawInfo : drawInfoList) {
                // 获取每个任务的详细信息,如果已经查找过则直接使用,如果没有则去数据库查找并存储
                if (taskInfoMap.containsKey(drawInfo.getTaskId())) {
                    drawInfo.setTaskInfo(taskInfoMap.get(drawInfo.getTaskId()));
                } else {
                    TaskInfo taskInfo = labelTaskDao.getTaskInfo(drawInfo.getTaskId());
                    drawInfo.setTaskInfo(taskInfo);
                    taskInfoMap.put(drawInfo.getTaskId(), taskInfo);
                }

                // 处理得到每个任务的具体结束时间
                Calendar cl = Calendar.getInstance();
                cl.setTime(drawInfo.getStartTime());
                cl.add(Calendar.HOUR, drawInfo.getTaskInfo().getLimitTime());
                drawInfo.setExpectedEndTime(cl.getTime());

                // 获得每个任务尚未完成的数量
                drawInfo.setUnFinishNum(labelTaskDao.getUnFinishedNum(drawInfo.getDrawId()));

                // 根据未完成数量设置紧急程度
                System.out.println(drawInfo.getUnFinishNum() / drawInfo.getTotalNum());
                double percent = (double) drawInfo.getUnFinishNum() / drawInfo.getTotalNum();
                if (percent > 0.8) {
                    drawInfo.setUrgentLevel("FCJJ");
                } else if (percent > 0.2) {
                    drawInfo.setUrgentLevel("JJ");
                } else {
                    drawInfo.setUrgentLevel("BJJ");
                }
            }

            return pageInfo;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    /**
     * 获得某次领取的领取详情,包括模板信息,任务信息,标注信息,第一个未标注的样本下标
     *
     * @param drawId 领取id
     * @return 领取详情
     */
    @Override
    public DrawDetail getDrawDetail(Integer drawId) {
        try {
            // 根据drawId获得taskId和templateId
            DrawDetailParam drawDetailParam = labelTaskDao.getBasicDrawInfo(drawId);

            DrawDetail drawDetail = new DrawDetail();
            // 获得模板情况
            Template template = templateService.getTemplateInfo(drawDetailParam.getTemplateId());
            drawDetail.setTemplate(template);

            // 获得任务详情
            Integer taskId = drawDetailParam.getTaskId();
            drawDetail.setTaskInfo(getTaskInfo(taskId));

            // 获得具体标注情况
            drawDetail.setMarkInfoList(getMarkInfoList(drawId));

            // 将标注情况进行排序,并得到当前第一个未标注文件的index
            Integer currentIndex = sortMarkInfoList(drawDetail.getMarkInfoList());
            drawDetail.setCurrentIndex(currentIndex);

            return drawDetail;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 获得具体的标注信息,包括模板信息,任务信息,标注信息
     * for Li Xiang
     *
     * @param taskId     任务id
     * @param markIdList 需要的标注详情列表id
     * @return 具体的标注信息
     */
    @Override
    public DrawDetail getDrawDetailById(Integer taskId, List<Integer> markIdList) {

        // 根据drawId获得taskId和templateId
        DrawDetailParam drawDetailParam = labelTaskDao.getBasicDrawInfoByTaskId(taskId);

        DrawDetail drawDetail = new DrawDetail();
        // 获得模板情况
        Template template = templateService.getTemplateInfo(drawDetailParam.getTemplateId());
        drawDetail.setTemplate(template);

        // 获得任务详情
        drawDetail.setTaskInfo(getTaskInfo(taskId));

        // 获得具体标注情况
        List<MarkInfo> markInfoList = labelTaskDao.getMarkInfoListById(markIdList);// 获得到具体的标注列表
        getMarkInfoDetail(markInfoList);
        drawDetail.setMarkInfoList(markInfoList);

        return drawDetail;

    }

    /**
     * 在设置每次领取的状态时同时检查当前任务是不是已经全部标注完成了,即检查当前任务状态是否为2,并且所有的领取的状态都为'YWC'
     * 如果上述条件满足则设置任务状态为3("未审核")
     *
     * @param taskId 任务id
     */
    @Override
    public void setTaskStatus(Integer taskId) {
        TaskInfo taskInfo = labelTaskDao.getTaskInfo(taskId);
        System.out.println(taskInfo.getTaskStatus());

        if (taskInfo.getTaskStatus() != 2) {
            return;
        }

        // 说明任务已经全部分发完成
        List<String> drawStatusList = labelTaskDao.getDrawListByTaskId(taskId);
        boolean flag = true;
        for (String status : drawStatusList) {
            if ("WWC".equals(status)) {
                flag = false;
                break;
            }
        }

        // 设置任务状态为3("未审核")
        if (flag) {
            labelTaskDao.setTaskFinish(taskId);
        }
    }


    /**
     * 将某次标注的结果集按照结束时间排序,同时得到第一个没有标注的样本的下标
     *
     * @param markInfoList 需要被排序的待标注信息列表
     * @return 第一个没有标注的样本的下标
     */
    private Integer sortMarkInfoList(List<MarkInfo> markInfoList) {
        markInfoList.sort((b, a) -> {
            if (a.getEndTime() == null && b.getEndTime() == null) {
                return 0;
            } else if (a.getEndTime() == null) {
                return -1;
            } else if (b.getEndTime() == null) {
                return 1;
            }
            return (int) (a.getEndTime().getTime() - b.getEndTime().getTime());
        });
        System.out.println(markInfoList);
        Integer ret = 0;
        for (int i = 0; i < markInfoList.size(); i++) {
            if (markInfoList.get(i).getEndTime() == null) {
                ret = i;
                break;
            }
        }
        System.out.println(ret);
        return ret;
    }

    /**
     * 获得某次领取的详细标注信息
     *
     * @param drawId 领取id
     * @return 某次领取的详细标注信息
     */
    public List<MarkInfo> getMarkInfoList(Integer drawId) {
        List<MarkInfo> markInfoList = labelTaskDao.getMarkInfoList(drawId);
        getMarkInfoDetail(markInfoList);

        return markInfoList;
    }

    /**
     * 获得标注的具体信息
     *
     * @param markInfoList 标注列表
     */
    public void getMarkInfoDetail(List<MarkInfo> markInfoList) {
        Map<Integer, MarkDetail> map = new HashMap<>();

        for (MarkInfo markInfo : markInfoList) {
            map.clear();
            // 获取该样本详情
            TaskContent taskContent = labelTaskDao.getTaskContent(markInfo.getContentId());
            markInfo.setTaskContent(taskContent);

            // 获取该用户的标注情况
            List<MarkDetail> markDetailList = labelTaskDao.getMarkDetailList(markInfo.getMarkId());
            int index = 0;
            while (index < markDetailList.size()) {
                MarkDetail markDetail = markDetailList.get(index);
                if (map.containsKey(markDetail.getAttrNameId())) {
                    map.get(markDetail.getAttrNameId()).append(markDetail.getAttrValue());// 说明前面以及有这个属性对应的值了,因此只需要把当前的值插入前面属性的列表中即可
                    markDetailList.remove(markDetail);
                } else {
                    map.put(markDetail.getAttrNameId(), markDetail);
                    markDetail.append(markDetail.getAttrValue());
                    markDetail.setAttrValue(null);
                    index++;
                }
            }

            markInfo.setMarkDetailList(markDetailList);
        }
    }

    /**
     * 获得任务详细信息
     *
     * @param taskId 任务id
     * @return 任务详细信息
     */
    @Override
    public TaskInfo getTaskInfo(Integer taskId) {
        return labelTaskDao.getTaskInfo(taskId);
    }

    /**
     * 修改标注结果
     *
     * @param markResult 标注结果集
     * @return 修改结果
     */
    @Override
    public boolean changeMarkResult(MarkResult markResult) {
        try {
            List<MarkInfo> changedMarkInfoList = new ArrayList<>();

            List<MarkDetail> newMarkDetailList = new ArrayList<>();
            List<Integer> deletedMarkDetailList = new ArrayList<>();

            for (MarkInfo markInfo : markResult.getMarkInfoList()) {
                if (markInfo.getUpdate() != 0) {
                    changedMarkInfoList.add(markInfo);
                }
                if (markInfo.getUpdate() == 1) {
                    // update为1表示更新
                    // 首先将库中markId对应的标注详情删掉,然后将本次标注结果再加进去
                    List<Integer> oldMarkDetailId = labelTaskDao.getOldMarkDetail(markInfo.getMarkId());
                    System.out.println(oldMarkDetailId);
                    deletedMarkDetailList.addAll(oldMarkDetailId);

                    for (MarkDetail markDetail : markInfo.getMarkDetailList()) {
                        // 获取需要更新的标注详情,需要将其attrValueList进行分解
                        newMarkDetailList.addAll(markDetail.decomposeMarkDetailList());
                    }
                } else if (markInfo.getUpdate() == 2) {
                    // update为2表示新增
                    markInfo.setStatus("DYS");//设置样本状态为待验收

                    for (MarkDetail markDetail : markInfo.getMarkDetailList()) {
                        // 需要新加的标注详情,首先需要设置markId,然后获得从attrValueList分解的参数
                        markDetail.setMarkId(markInfo.getMarkId());
                        newMarkDetailList.addAll(markDetail.decomposeMarkDetailList());
                    }

                }
            }

            labelTaskDao.changeMarkInfo(changedMarkInfoList);// 修改原有标注结果信息

            if (deletedMarkDetailList.size() > 0) {
                labelTaskDao.deleteMarkInfoDetail(deletedMarkDetailList);// 删除被舍弃的标注信息
            }

            if (newMarkDetailList.size() > 0) {
                labelTaskDao.addMarkInfoDetail(newMarkDetailList);// 添加新的标注信息
            }


            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}
